﻿using Microsoft.AspNetCore.Hosting.Server;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace senlv.Models
{
    public class MapHelper
    {
        string[] pointsArray = {
        "{ lat: 19.294005, lng: 109.525726 },",
        "{ lat: 19.295305, lng: 109.525122 },",
        "{ lat: 19.295469, lng: 109.524929 },",
        "{ lat: 19.296050, lng: 109.524810 },",
        "{ lat: 19.296844, lng: 109.524485 },",
        "{ lat: 19.297355, lng: 109.524506 },",
        "{ lat: 19.297396, lng: 109.524023 },",
        "{ lat: 19.298221, lng: 109.524018 },",
        "{ lat: 19.298647, lng: 109.523755 },",
        "{ lat: 19.298789, lng: 109.524064 },",
        "{ lat: 19.298302, lng: 109.524353 },",
        "{ lat: 19.297976, lng: 109.524795 },",
        "{ lat: 19.296215, lng: 109.525183 },",
        "{ lat: 19.298098, lng: 109.522711 }," };
        //老周三村14点邻接矩阵
        static int[,] Metro = new int[14, 14] {
           //0    1     2     3   4   5     6   7     8    9   10    11   12  13
            {0  ,145 ,9999,9999,9999,9999,9999,9999,9999,9999,9999,9999,9999,9999},//0
            {145 ,0  ,18 ,9999,9999,9999,9999,9999,9999,9999,9999,9999,9999,9999},//1
            {9999,18  ,0  ,65 ,9999,9999,9999,9999,9999,9999,9999,9999,9999,9999},//2
            {9999,9999,65  ,0  ,88 ,9999,9999,9999,9999,9999,9999,9999,18  ,9999},//3
            {9999,9999,9999,88  ,0  ,57 ,9999,9999,9999,9999,9999,9999,9999,9999},//4
            {9999,9999,9999,9999,57  ,0  ,45 ,9999,9999,9999,9999,69  ,9999,9999},//5
            {9999,9999,9999,9999,9999,45  ,0  ,92 ,9999,9999,9999,9999,9999,9999},//6
            {9999,9999,9999,9999,9999,9999,92  ,0  ,47 ,9999,9999,9999,9999,9999},//7
            {9999,9999,9999,9999,9999,9999,47  ,9999,0  ,16 ,9999,9999,9999,61},//8
            {9999,9999,9999,9999,9999,9999,9999,9999,16  ,0  ,54 ,9999,9999,9999},//9
            {9999,9999,9999,9999,9999,9999,9999,9999,9999,54  ,0  ,36  ,9999,9999},//10  
            {9999,9999,9999,9999,9999,69  ,9999,9999,9999,9999,9999,0  ,9999,9999},//11
            {9999,9999,9999,18  ,9999,9999,9999,9999,9999,9999,9999,9999,0  ,9999},//12
            {9999,9999,9999,9999,9999,9999,9999,9999,61,9999,9999,9999,9999 ,0  }//13
        };
        static int row = 14;
        ArrayList S = new ArrayList(row);//S储存确定最短路径的顶点的下标
        ArrayList U = new ArrayList(row);//U中存储尚未确定路径的顶点的下标
        int[] distance = new int[14];//用以每次查询存放数据
        int[] prev = new int[14];//用以存储前一个最近顶点的下标
        bool[] Isfor = new bool[14] { false, false, false, false, false, false, false, false, false, false, false, false, false, false };
        /// <summary>
        /// dijkstra算法的实现部分
        /// </summary>
        /// <param name="Start"></param>
       public void FindWay(int Start)
        {
            S.Add(Start);
            Isfor[Start] = true;
            for (int i = 0; i < row; i++)
            {
                if (i != Start)
                    U.Add(i);
            }
            for (int i = 0; i < row; i++)
            {
                distance[i] = Metro[Start, i];
                prev[i] = 0;
            }
            int Count = U.Count;
            while (Count > 0)
            {
                int min_index = (int)U[0];//假设U中第一个数存储的是最小的数的下标
                foreach (int r in U)
                {
                    if (distance[r] < distance[min_index] && !Isfor[r])
                        min_index = r;
                }
                S.Add(min_index);//S加入这个最近的点
                Isfor[min_index] = true;
                U.Remove(min_index);//U中移除这个点；
                foreach (int r in U)
                {
                    //查找下一行邻接矩阵，如何距离和上一个起点的距离和与数组存储的相比比较小，就更改新的距离和起始点,再比对新的起点到各边的距离
                    if (distance[r] > distance[min_index] + Metro[min_index, r])
                    {
                        distance[r] = distance[min_index] + Metro[min_index, r];
                        prev[r] = min_index;
                    }
                    else
                    {
                        distance[r] = distance[r];
                    }
                }
                Count = U.Count;
            }
        }



        /// <summary>
        /// 把生成数据显示出来
        /// </summary>
       public string display(int starNum, int endNum)
        {
            string contentStr = "";
            string lineJson = fileToString("oldweek3.txt");//mapName + 
            List<Jpoint> jpoints = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Jpoint>>(lineJson);
            //for (int i = 0; i < row; i++)
            // {
            int i = endNum;
            Console.Write("V" + starNum + "到V{0}的最短路径为", i);
            int prePoint = prev[i];
            string s = "";
            StringBuilder sb = new StringBuilder(10);

            while (prePoint > 0)
            {

                s = (prePoint) + s;
                prePoint = prev[prePoint];

            }
            //Console.Write("-V1");
            for (int j = 0; j < s.Length; j++)
            {
                switch(s[j])
                {
                    case '0':
                        contentStr += pointsArray[0];
                        break;
                    case '1':
                        contentStr += pointsArray[1];
                        break;
                    case '2':
                        contentStr += pointsArray[2];
                        break;
                    case '3':
                        contentStr += pointsArray[3];
                        break;
                    case '4':
                        contentStr += pointsArray[4];
                        break;
                    case '5':
                        contentStr += pointsArray[5];
                        break;
                    case '6':
                        contentStr += pointsArray[6];
                        break;
                    case '7':
                        contentStr += pointsArray[7];
                        break;
                    case '8':
                        contentStr += pointsArray[8];
                        break;
                    case '9':
                        contentStr += pointsArray[9];
                        break;
                    default:
                        break;

                }
               // Console.WriteLine(s[j]);
               // sb.Append("-V").Append(s[j]);
            }
            //Console.Write(sb.ToString());
            //Console.WriteLine(":{0}", distance[i]);
            return contentStr;
            //}

        }

        public class Jpoint
        {
            public double lat { get; set; }
            public double len { get; set; }
        }
        public class pointList
        {
           public List<Jpoint> jpoints { get; set; } = new List<Jpoint>();
        }
        /// <summary>
        /// 读取文本内容
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public string fileToString(string filePath)
        {
            string strData = "";
            try
            {
                string line;
                // 创建一个 StreamReader 的实例来读取文件 ,using 语句也能关闭 StreamReader
                using (System.IO.StreamReader sr = new System.IO.StreamReader(filePath))
                {
                    // 从文件读取并显示行，直到文件的末尾 
                    while ((line = sr.ReadLine()) != null)
                    {
                        strData += line;
                    }
                }
               
            }
            catch (Exception e)
            {
                // 显示出错消息
                Console.WriteLine("The file could not be read:");
                Console.WriteLine(e.Message);
            }
            return strData;
        }
        private const double EARTH_RADIUS = 6378137;
        /// <summary>
        /// 计算两点位置的距离，返回两点的距离，单位 米
        /// 该公式为GOOGLE提供，误差小于0.2米
        /// </summary>
        /// <param name="lat1">第一点纬度</param>
        /// <param name="lng1">第一点经度</param>
        /// <param name="lat2">第二点纬度</param>
        /// <param name="lng2">第二点经度</param>
        /// <returns></returns>
        public static double GetDistance(double lat1, double lng1, double lat2, double lng2)
        {
            double radLat1 = Rad(lat1);
            double radLng1 = Rad(lng1);
            double radLat2 = Rad(lat2);
            double radLng2 = Rad(lng2);
            double a = radLat1 - radLat2;
            double b = radLng1 - radLng2;
            double result = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2))) * EARTH_RADIUS;
            return result;
        }
        /// <summary>
        /// 经纬度转化成弧度
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        private static double Rad(double d)
        {
            return (double)d * Math.PI / 180d;
        }

        //public string lineStr(string mapName)
        //{
        //        switch (mapName)
        //        {
        //            case "oldweek3":
                       
        //                Console.WriteLine(lineJson);
        //            using (System.IO.StreamWriter file = new System.IO.StreamWriter("DistanceOut.txt", true))
        //            {
        //                for (int i = 0; i < jpoints.Count-1; i++)
        //                {
        //                    file.WriteLine("["+i+"]->[new]="+GetDistance(jpoints[i].lat, jpoints[i].len, jpoints[i + 1].lat, jpoints[i + 1].len)); 
        //                }
        //            }
                  
        //            return jpoints[1].lat.ToString();
        //            default:
        //                return null;
        //        }    
        //}


        /// <summary>
        /// 计算三点夹角角度
        /// 点：Point point=new Point(构造);
        /// </summary>
        /// <param name="cen"></param>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        public static double Angle(Point cen, Point first, Point second)
        {
            const double M_PI = 3.1415926535897;
            double ma_x = first.X - cen.X;
            double ma_y = first.Y - cen.Y;
            double mb_x = second.X - cen.X;
            double mb_y = second.Y - cen.Y;
            double v1 = (ma_x * mb_x) + (ma_y * mb_y);
            double ma_val = Math.Sqrt(ma_x * ma_x + ma_y * ma_y);
            double mb_val = Math.Sqrt(mb_x * mb_x + mb_y * mb_y);
            double cosM = v1 / (ma_val * mb_val);
            double angleAMB = Math.Acos(cosM) * 180 / M_PI;
            return angleAMB;
        }

      
    }
}
